在還沒有加入Redux之前,資料在APP中各個view的傳遞會需要翻山越嶺,經過一個庄再到一庄:
有了 Redux 後,所有的資料就會在最上層直接存取,就會像這樣直接升級!:
如此一來直接收斂資料流可以避免掉資料四散的問題,也可以讓資料流更好整理。
在改變參數的過程中,我們會在 view 發出一個 action ,這個 action 會在 Reducer 中,看對應到哪一個動作,就去執行你要做的 function,再來改變 store 中的值顯示在畫面中。
放資料的地方,可以當作資料的集散地,在Redux中只會有一個 Store(Single source is turth)。
在 ./src/app/store/
中建立一個 configureStore.js
加入下面的內容
import { configureStore } from '@reduxjs/toolkit'
export default configureStore({
reducer: {} // 這邊我們會引入 redcuer 稍後會提到
})
在 app.js 中加入:
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import store from './app/store/confiureStore';
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
我們主要有兩種方式來直接存取 store
的值。
在頁面中,我們可以透過 Container
、一個最外層的容器,來連結 view
:
import { connect } from 'react-redux';
import Home from './view';
const mapStateToProps = ({ auth }) => ({
username: auth.username
});
const mapDispatchToProps = (dispatch) => ({
//
});
export default connect(mapStateToProps, mapDispatchToProps)(Home);
如此一來 Home
就可以透過 props
來存取到 username
這個值
import React from 'react';
import { Text } from 'react-native';
const Home = ({ username }) => {
return <Text>{username}</Text>
}
export default Home;
使用 Hook 就不用從外部的 props 傳遞資料進來,直接在 view 中就可以存取。
import React from 'react';
import { Text } from 'react-native';
import { useSelector } from 'react-redux';
const Home = () => {
const username = useSelector(({ auth }) => auth.username);
return <Text>{username}</Text>
}
export default Home;
改變的過程比較複雜,首先我們要發出一個 action
,發出的 action 經過 dispatch
來到 Reducer
中,再依照 actionType
,來看要做什麼事情。
action
是一個 pure function
,舉例來說,我要進行一個 改變 username 的動作
,那我的 action 可以這樣寫:
const editUsernameAction = (payload) => ({
type: 'EDIT_USERNAME', // actionType 用來識別進入 Reducer 要做什麼事
payload //帶入的參數
})
在 mapDispatchToProps
中,加入我們上面提到的 editUsernameAction
。
import { connect } from 'react-redux';
import { editUsernameAction } from '~/actions/userActions'
import Home from './view';
const mapStateToProps = ({ auth }) => ({
username: auth.username
});
const mapDispatchToProps = (dispatch) => ({
handleUpdateUsernem: payload => {
dispatch(editUsernameAction(payload));
}
});
export default connect(mapStateToProps, mapDispatchToProps)(Home);
如此一來就可以在 Home
中用 props 找到 handleUpdateUsernem
。
以下是在 input 中輸入 username,按下送出來更新 username:
import React, {useState} from 'react';
import { Text, TextInput, View, Button } from 'react-native';
const Home = ({ username, handleUpdateUsernem }) => {
const [ payload, setPayload ] = useState('');
return (
<View>
<Text>{username}</Text>
<TextInput value={payload} onChange={value => setPayload(value)}/>
<Button title="送出" onPress={ () => handleUpdateUsernem(payload)}/>
</View>
)
}
export default Home;
使用 Hook 就是把 dispatch 這段拿到 view 中:
import React, {useState} from 'react';
import { useSelector } from 'react-redux';
import { Text, TextInput, View, Button } from 'react-native';
import { editUsernameAction } from '~/actions/userActions'
const Home = ({ username, handleUpdateUsernem }) => {
const [ payload, setPayload ] = useState('');
const username = useSelector(({ auth }) => auth.username);
const dispatch = useDispatch(); // 這邊拿到 dispatch
const handleUpdateUsernem = () => {
dispatch(editUsernameAction(payload)); // 這邊去呼叫他
}
return (
<View>
<Text>{username}</Text>
<TextInput value={payload} onChange={value => setPayload(value)}/>
<Button title="送出" onPress={handleUpdateUsernem}/>
</View>
)
}
export default Home;
我們在 ./src/reducers/
中建立一個 userReducer.js
export default function reducer(user = userState, { type, payload }) {
switch (type) {
case 'EDIT_USERNAME':
return { ...user, username: payload };
default:
return user;
}
}
在 ./src/reducers/
中建立一個 index.js
。接著我們要將所有的 reducer 疊加再一起,這時候我們會用到 combineReducers
:
import user from './userReducer';
export default combineReducers({
user
});
import { configureStore } from '@reduxjs/toolkit'
import reducer from '~/src/reducer';
export default configureStore({
reducer // 這邊我們會引入上方的 combine 後的 reducer
})
這樣我們的一個資料循環就完成了: